const AppError = require('../utils/appError')
const User = require('../models/user')
const jwtUtil = require('../utils/jwtUtil')
const catchAsync = require('../utils/catchAsync')
const client = require('../utils/redisClient')

/**
 * 添加管理管
 * 临时使用
 */
exports.addAdmin = catchAsync(async (req, res, next) => {
  const user = new User(req.body)
  const savedUser = await user.save()

  res.json({
    status: 'success',
    message: '管理员添加成功',
    data: savedUser,
  })
})

// 获取管理员信息
exports.adminGetInfo = catchAsync(async (req, res, next) => {
  const admin = await User.findOne({ role: 'admin', username: 'akbar' }).select('-password')
  if (!admin) {
    return next(new AppError('管理员不存在', 404))
  }
  res.status(200).json({
    status: 'success',
    data: admin,
  })
})

/**
 * 管理员登录
 * @type {(function(*, *, *): void)|*}
 */
exports.adminLogin = catchAsync(async (req, res, next) => {
  const { username, password, captcha, captchaId } = req.body

  // 检查用户名和密码是否为空
  if (!username || !password || !captcha || !captchaId) {
    return next(new AppError('请输入登录信息', 400))
  }

  // 从redis中获取验证码
  const savedCaptcha = await client.get(`captcha:${captchaId}`)
  if (!savedCaptcha || savedCaptcha !== captcha.toLowerCase()) {
    return next(new AppError('验证码错误或已过期', 400))
  }

  // 检查用户是否存在
  let user = await User.findOne({ username }).select('+password')

  if (!user || !(await user.correctPassword(password, user.password))) {
    return next(new AppError('用户名或者密码错误', 400))
  }

  // 判断角色
  if (!['admin', 'visitor'].includes(user.role)) {
    return next(new AppError('用户名或者密码错误', 400))
  }

  // 生成jwt token
  const token = jwtUtil.signToken(user._id)

  // 存到redis中
  await client.setEx(`token:${user._id}`, +process.env.REDIS_TOKEN_EXPIRES_IN, token)

  user = user.toObject()
  delete user.password
  res.status(200).json({
    status: 'success',
    message: '登陆成功',
    data: {
      token,
      user,
    },
  })
})

/**
 * 管理员退出登录
 * 需要--拦截器中间(提前获取到user和token信息)
 * @type {(function(*, *, *): void)|*}
 */
exports.adminLogout = catchAsync(async (req, res, next) => {
  // 删除redis中的token
  await client.del(`token:${req.user._id}`)

  // 把这个token放入redis黑名单
  await client.setEx(`blacklist:${req.token}`, +process.env.REDIS_TOKEN_EXPIRES_IN, 'true')

  res.status(200).json({ status: 'success', message: '已登出' })
})

/**
 * 管理员更新密码
 * 需要--拦截器中间(提前获取到user和token信息)，权限验证
 * @type {(function(*, *, *): void)|*}
 */
exports.adminUpdatePassword = catchAsync(async (req, res, next) => {
  const { newPassword, confirmPassword } = req.body

  if (!newPassword || !confirmPassword) return next(new AppError('请输入新密码和确认密码', 400))

  if (newPassword !== confirmPassword)
    return next(new AppError('两次输入的密码不一致，请重新输入', 400))

  const user = await User.findById(req.params.id).select('+password')
  if (!user) {
    return next(new AppError('该用户不存在', 404))
  }

  // 更新
  user.password = newPassword
  await user.save()

  // 更新用户的token
  const newToken = jwtUtil.signToken(user._id)
  await client.del(`token:${user._id}`)
  await client.setEx(`blacklist:${req.token}`, +process.env.REDIS_TOKEN_EXPIRES_IN, 'true')
  await client.setEx(`token:${user._id}`, +process.env.REDIS_TOKEN_EXPIRES_IN, newToken)

  res.status(200).json({ status: 'success', message: '密码修改成功', data: newToken })
})

/**
 * 管理员更新其它信息
 * 需要--拦截器中间(提前获取到user和token信息)，权限验证
 * @type {(function(*, *, *): void)|*}
 */
exports.adminUpdateInfo = catchAsync(async (req, res, next) => {
  // 为了防止管理员信息意外修改，这里要解构出需要的信息
  const adminInfo = {
    name: req.body.name,
    email: req.body.email,
    avatar: req.body.avatar,
    github: req.body.github,
    gitee: req.body.gitee,
    juejin: req.body.juejin,
    description: req.body.description,
  }

  let user = await User.findByIdAndUpdate(req.params.id, adminInfo, {
    runValidators: true,
    new: true,
  })

  if (!user) {
    return next(new AppError('该用户不存在', 404))
  }

  user = user.toObject()
  delete user.password
  res.status(200).json({
    status: 'success',
    message: '用户信息更新成功',
    data: user,
  })
})
